<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>图片瑕疵修复</title>
    <!--COS SDK-->
    <script src="https://cdn.jsdelivr.net/npm/cos-js-sdk-v5/dist/cos-js-sdk-v5.min.js"></script>
  </head>
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
    }
    .container {
      padding: 20px;
    }
    #canvas {
      position: absolute;
      z-index: 9;
      left: 0;
      background-color: rgba(255, 255, 255, 0);
    }
  </style>
  <body>
    <div class="container">
      <button onclick="uploadImg()">开始修复</button>
      <p>原图：<span id="textMsg"></span></p>
      <div style="position: relative">
        <img id="imgId1" />
        <canvas id="canvas"></canvas>
      </div>
      <div>
        <p>效果图：</p>
        <img id="imgId2" />
      </div>
    </div>
    <script>
      const canvas = document.getElementById('canvas');
      const textMsg = document.getElementById('textMsg');
      //原图真实大小
      let originWidth = 0,
        originHeigh = 0;

      /* 准备工作：
       1. 在cos控制台创建一个存储桶，可拿到存储桶名称和地域，即Bucket，Region。
       2. 进入存储桶配置页面，设置对应的跨域规则（简单调试可将来源Origin设置为*）。
       3. 上传待修复的图片文件到存储桶中。
       4. 进入访问管理控制台，获取API密钥，即SecretId，SecretKey。
      */

      // 存储桶配置请在cos控制台获取。https://console.cloud.tencent.com/cos/bucket
      // 格式参考：Bucket: 'abc-1250000000', Region: 'ap-shanghai'，FileName：'demo.png'
      const config = {
        // 需要替换成您自己的存储桶信息
        Bucket: '***-125********' /* 存储桶，必须 */,
        Region: '**-*****' /* 存储桶所在地域，必须字段 */,
        FileName: 'demo.png' /* 上传到原图文件名, 必须  */,
      };

      // 注意：以下初始化方式仅供联调测试使用，为了安全起见，请勿在生产环境直接暴露密钥。
      // 生产环境请参考各语言SDK签名实现。https://cloud.tencent.com/document/product/436/7778#sdk-.E7.AD.BE.E5.90.8D.E5.AE.9E.E7.8E.B0

      // 密钥请在访问管理控制台获取。https://console.cloud.tencent.com/cam/capi
      const cos = new COS({
        SecretId: '*******************',
        SecretKey: '*******************',
      });

      /*  操作步骤：
       1. 预先将原图上传到cos存储桶中。
       2. 根据原图尺寸，初始化用于涂抹的canvas画布。
       3. 使用鼠标在canvas上标记涂抹的区域，涂抹完成后将canvas遮罩图上传到cos存储桶中。
       4. 遮罩图上传成功后获取携带图像修复相关参数的url可访问地址。
      */

      // 原图地址
      const imgSrc = `https://${config.Bucket}.cos.${config.Region}.myqcloud.com/${config.FileName}`;
      document.getElementById('imgId1').src = imgSrc;

      // 获取图片尺寸初始化画布
      const img = new Image();
      textMsg.innerHTML = '...加载中';
      img.crossOrigin = 'anonymous'; // 跨域设置，必须
      img.onload = () => {
        const context = canvas.getContext('2d');
        originWidth = img.width;
        originHeight = img.height;
        // 画板大小
        canvas.width = originWidth;
        canvas.height = originHeight;
        context.clearRect(0, 0, originWidth, originHeight);
        textMsg.innerHTML = '请按住鼠标，选择修复区域';

        // 绑定画布绘制方法事件
        setCanvasDraw(context);
      };
      img.src = imgSrc;

      // 上传涂抹区域并请求图片修复
      function uploadImg() {
        // 绘制涂抹区域图
        getImgBlob(blob => {
          {
            blob.name = '****.jpg'; /** 涂抹区域图文件名 */
            // 上传涂抹区域
            cos.putObject(
              {
                Bucket: config.Bucket,
                Region: config.Region,
                Key: blob.name,
                Body: blob,
                onProgress: progressData => console.log('上传中，' + JSON.stringify(progressData)),
              },
              (err, data) => {
                if (err) {
                  console.log(JSON.stringify(err));
                  textMsg.innerHTML = '修复区域上传失败';
                  return;
                }
                // 生成带图片处理参数的签名 URL。
                // 图像修复请求及参数格式，可参考文档 https://cloud.tencent.com/document/product/460/82387
                cos.getObjectUrl(
                  {
                    Bucket: config.Bucket,
                    Region: config.Region,
                    Method: 'GET',
                    Key: config.FileName,
                    Query: {
                      'ci-process': 'ImageRepair' /** 固定值，必须 */,
                      MaskPic: btoa(`https://${data.Location}`) /** 遮罩（白色区域为需要去除的水印位置）图片地址,需要经过 URL 安全的 Base64 编码 */,
                    },
                    Expires: 1800,
                    Sign: true,
                  },
                  (err, data) => {
                    if (err) {
                      console.log(JSON.stringify(err));
                      textMsg.innerHTML = '图片修复失败';
                      return;
                    }
                    document.getElementById('imgId2').src = data.Url;
                    console.log(err, data);
                  }
                );
              }
            );
          }
        });
      }

      // 画布绘制操作
      function setCanvasDraw(context) {
        let isDrawing = false;
        let x = 0;
        let y = 0;
        const drawLine = (context, x0, y0, x1, y1) => {
          context.beginPath();
          context.strokeStyle = 'white';
          context.lineWidth = 30;
          context.moveTo(x0, y0);
          context.lineTo(x1, y1);
          context.lineJoin = 'round';
          context.lineCap = 'round';
          context.stroke();
        };
        canvas.addEventListener('mousedown', event => {
          x = event.layerX;
          y = event.layerY;
          isDrawing = true;
        });

        canvas.addEventListener('mousemove', event => {
          if (isDrawing) {
            drawLine(context, x, y, event.layerX, event.layerY);

            x = event.layerX;
            y = event.layerY;
          }
        });

        canvas.addEventListener('mouseup', event => {
          if (isDrawing) {
            drawLine(context, x, y, event.layerX, event.layerY);
            x = 0;
            y = 0;
            isDrawing = false;
          }
        });
      }

      // 绘制涂抹区域
      const getImgBlob = callback => {
        let dataUrl = canvas.toDataURL('image/jpeg');
        let img = new Image();
        img.onload = () => {
          let canvas2 = document.createElement('canvas');
          canvas2.width = originWidth;
          canvas2.style.backgroundColor = '#000';
          canvas2.height = originHeight;
          let ctx = canvas2.getContext('2d');
          ctx.drawImage(img, 0, 0, originWidth, originHeight);
          canvas2.toBlob(callback);
        };
        img.src = dataUrl;
      };
    </script>
  </body>
</html>
